Table of Contents

 

 

                                    Section 1 -                   What will to make?

                                    Section 2 -                   Adding the save function

                                    Section 3 -                   Making some Media

                                    Section 4 -                   Constructing the Game Engine

                                    Section 5 -                   Full Game Engine Source

                                    Section 6 -                   Notes and Closing

 

 

 

Section 1 - What Will We Make ?

 

            Today we will be finishing off our Tile Editor, and then we’ll be putting it to use as we start the beginnings of our own little game.

 

            The checklist of objectives:

            - Add a save/load function to our tile editor.

            - Making some media.

            - Construct a game engine using the base code from our Tile Editor

            - Load our level from the tile editor into our game.

            - Add collision into our game engine.

            - Add a scrolling background into our game engine.

            - Create and move around our hero player.

 

 

 

 

 

 

 

 

 

 

 

 

Section 2 - Adding the save function

 

            When saving a level of any type, it’s important that you have in mind some sort of format so that it can always be loaded and edited again.  Sometimes it’s also handy to encrypt the loaded file so users can’t mess with you game in a way it wasn’t meant to be played.  For our level editor, our format is very simple. We’ll start out by writing the variables Dimension, TileSize, and Mapsize. Once those are written into a file, we can one by one, write out the value of each individual tile into the same file.  Once that’s done, all we have to do is add a simple if-statement in our main loop to use the function.

 

Here is our save function that can be pasted at the very bottom of our source code.

function SaveLevel( _Dimensions, _TileSize, _MapSize)

input "",filename$

if file exist(filename$) then delete file filename$

open to write 1,filename$

  write string 1,str$(_Dimensions)

  write string 1,str$(_TileSize)

  write string 1,str$(_MapSize)

 

  for x = 0 to MapSize

  for y = 0 to MapSize

    write string 1,str$(Grid(x,y))

  next x

  next y

 

close file 1

 

endfunction

 

Now just paste this anywhere inside our main loop, and when enter is pressed, type in whatever you want the file to be saved as.

if shiftkey()=1 then SaveLevel(Dimensions, TileSize, MapSize) 

 

Still having problems getting this to work? Don’t worry, the source and the level we’ll be using is included.

 

If you want to take things a bit further, and encrypt your files, here’s something you could do.

 

Change the for-next statement in your function to this when writing a string.

 

 

 

 

 

 

 

  for x = 0 to MapSize

  for y = 0 to MapSize

    if (Grid(x,y))=1 then write string 1,"???X?X?D"

    if (Grid(x,y))=2 then write string 1,"?FEX?X?D"

    if (Grid(x,y))=3 then write string 1,"?B?X?X?D"

    if (Grid(x,y))=4 then write string 1,"ZZUX?X?D"

    if (Grid(x,y))=5 then write string 1,"??%#@X?D"

  next x

  next y

 

For this tutorial, I will be using what was mentioned above for simplicity. Keep in mind though, simple tricks like using “weird” combination of characters are enough to keep the average user from messing with your level. I’ve included both the encrypted and unencrypted files, so go ahead and peek into each of them and see which is more intimidating. J

 

Oh yeah, almost forgot, you’ll probably want to reload that level into your editor incase you want to make changes. ;) So we’ll do almost exactly as we did in our save function with a few minor changes.

 

`Our load level function.

function LoadLevel()

input "",filename$

if file exist(filename$) then open to read 1,filename$

  read string 1,str$(_Dimensions)

  read string 1,str$(_TileSize)

  read string 1,str$(_MapSize)

 

`Re-assign our constants, in case they've changed.

#Constant Dimensions _Dimensions

#Constant TileSize _TileSize

#Constant MapSize _MapSize

 

`Read our values from the text file, then convert the values from a string

`variable, to a integer. Then, once it's an integer, we assign it back to our

`array.

  for x = 0 to MapSize

  for y = 0 to MapSize

    read string 1,str$(Grid(x,y))

    Grid(x,y)=val(str$(Grid(x,y)))

  next x

  next y

 

close file 1

 

endfunction

Then, when you want to load your level, do the same as before. Once you press control, just type in the filename of the level you want to load.

if controlkey()=1 then LoadLevel()

 

Holy moly/cow/fuzzily/insert_saying_here , that’s quite a bit to think about just save and load a level. The good news is though, it’s just two simple functions, two simple if-statements, and we’re done! As I mentioned before, be sure to check out the new source for the tile editor.

 

 

 

 

Section 3 - Making some media

 

            My choice of tools for this is PSP8.1. No, no, don’t worry if you don’t own it! They offer a 30 day trial version that you can download free. Either way, I would never force you to use a tool, pick you one you like best. The concepts in this quick mini tutorial for creating our content can be applied to all 2D art packages.

 

All the media used in this tutorial is of course included, so feel free to skip this part if you just want to dive into the code. J


1.) Okay, so now that you’ve got your tool of choice ready, open it up and create a new document 32x32 pixels in size.

 

2.) You should have a blank document open, and ready to paint on. Go ahead and use the paint bucket and make the whole think a light grey(192,192,192 rgb). See figure 3.1

 

3.) Now I want you to make a grid.

With PSP, we can do Effects -> Texture Effects -> Tiles.

(Make sure the TileSize is set to 32)                  See figure 3.2

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Figure3.1

Figure 3.2

 

 

4.) This is all you really need to create a simple tile for our tile game we’ll be making.  It’s important that you make sure the tiles are seamless, meaning they’ll line up perfectly no matter which side you line them up against.  I’ll take things a step further now using PSP to add a little bit of detail.

Effects -> Texture Effects -> Texture(fur 02)     See figure 3.3

 

5.) Just to ensure that our tile is seamless, PSP has a nice seamless image effect.

Effects -> Image Effects -> Seamless Tiling                   See figure 3.4

 

Figure 3.3

 

 

 

 

 

 

 

 

 

 

 

 

Figure 3.4

 

Before you know it, we have tons of tiles that we can put to use in our engine.

 

Section 4 - Constructing the Game Engine

 

            Okay, here we go, onto the big one.  We’ve got a level editor, a level, a good concept of scrolling, and all of our media in place (Check the newly created media folder in our project to see).  All the concepts we used earlier to make our level editor will be used here.  The great thing is, we can pretty much copy and paste all of our code and eliminate the entire tile editing stuff for the base of this. Check out the full source now!

I highly recommend you go ahead and copy&paste it all right into your DBP ide of choice, and preview what exactly you’re making. Then, go ahead and digest it comment by comment, and line by line.

 

Section 5 - Full Game Engine Source

`Didn't see last months tutorial? Get it here.

`http://www.thegamecreators.com/data/newsletter/newsletter_issue_34.html#14

 

 

`Here is our basic setup, the same as in our tile editor.

flush video memory

sync on : sync rate 60

backdrop on

set display mode 640,480,32

set window size 640,480

 

`Set the window title to whatever you want, for now we'll use "The Game Engine"

set window title "The Game Engine"

 

 

`Now we get to load our level into our game engine. We've had to make a few simple changes

`from our previous load function, but the base of this is just the same.

filename$="Level1"

if file exist(filename$) then open to read 1,filename$

  read string 1,_Dimensions$

  read string 1,_TileSize$

  read string 1,_MapSize$

 

 

`Once we read the Dimension, TileSize, and MapSize variables, we store their values in

`an integer.

_Dimensions=val(Dimensions$)

_TileSize=val(TileSize$)

_MapSize=val(_MapSize$)

 

`Re-assign our constants, in case they've changed from our new variables..

#Constant Dimensions _Dimensions

#Constant TileSize _TileSize

#Constant MapSize _MapSize

 

`Now we create our Grid array which stores the whole level data, and the Display array,

`which displays what's currently on screen.

dim Grid(MapSize,MapSize)

dim Display(Dimensions,Dimensions)

 

`Read our values from the text file, then convert the values from a string

`variable, to a integer. Then, once it's an integer, we assign it back to our

`array.

  for x = 0 to MapSize

  for y = 0 to MapSize

    read string 1,temp$

    Grid(x,y)=val(temp$)

    `Determines the starting position of our little hero.

    `Whichever tile is number 4, will be designated our starting spot for our hero

    `character.  So we assign the startx/starty values with the proper x and y values.

    `from their, we can also assign our hero's x and y position.

    if Grid(x,y)=4

      startx=x+1: herox=startx

      starty=y: heroy=starty

    endif

  next x

  next y

 

close file 1 `Close our file now that we're done with it.

 

 

`Now we get to load our media that we created.

load image "media/2.bmp",2

load image "media/3.bmp",3

load image "media/4.bmp",4

load image "media/5.bmp",5

load image "media/6.bmp",6

 

 

 

`For now, image one will just be black.

cls rgb(0,0,0)

get image 1,0,0,32,32

 

`Our Hero

#Constant Hero 10

load image "media/hero.bmp",Hero

`Our background: We'll need two of the same images for this.

#constant backgroundimage 11

#constant backgroundimage2 11

load image "media/background.bmp",backgroundimage,1

load image "media/background.bmp",backgroundimage2,1

 

`Our main loop

do

`cls `clear the screen.

 

 

`The base of this collision code works by getting the boundaries and making sure that

`your hero player doesn't cross them. I've also setup the basis for which we'll be able

`to do tile to tile collisions. The basis of this works in that our hero is just a mobile

`tile. However, this will be okay for now, and you can tweak it to your protection, although

`next month the whole tutorial will be dedicated to pixel-perfect collision. :)

 

if leftkey()=1 and currentx>0

  if RelativeTileX>0 `and Display(relativeTileX,relativeTileY)=1

    currentx=currentx-1

    herox=herox-1

  endif

endif

 

if rightkey()=1 and currentx<MapSize `and Display(relativeTileX,relativeTileY)=1

  currentx=currentx+1

  herox=herox+1

endif

 

if downkey()=1 and currenty<(MapSize-1)

  if RelativeTileY>0 `and Display(relativeTileX,relativeTileY)=1

    currenty=currenty+1

    heroy=heroy+1

  endif

endif

 

if upkey()=1 and currenty>0 `and Display(relativeTileX,relativeTileY)=1

  currenty=currenty-1

  heroy=heroy-1

endif

 

 

`This ensures that our hero doesn't go outside our screen. If he does, then the hero

`character will be reset back to the front of the screen.

if herox>Dimensions

  herox=0

endif

if heroy>Dimensions

  heroy=0

endif

if herox<0 then herox=Dimensions

if heroy<0 then heroy=Dimensions

 

 

 

`Here we'll paste our scrolling background.

`The way this works is we have two images 1024x768 in size. The y position will always

`be relative to the player. Meanwhile, both images are scrolling, but they're set their

`width apart so they're side by side. Once the backgroundx variable gets larger than 1024,

`it resets, and the process restarts to give you an infinitly scrolling background.

paste image backgroundimage,backgroundx,currenty

paste image backgroundimage,-1024+backgroundx,currenty

backgroundx=backgroundx+1

if backgroundx>1024 then backgroundx=0

 

 

 

 

`Here is the simple for-next loop that breaks everything down.

`For the current dimensions, the GRID array data is applied to our DISPLAY array.

`This is then the array that we use to paste the various images to the screen with.

for x = 0 to Dimensions

for y = 0 to Dimensions

  if currentx+x>MapSize or currenty+y>MapSize `Ensure we're not out of bounds on our array.

    Display(x,y)=Grid(150,150)                `If we are, just assign the last GRID value.

  else                                        `If we're not out of bounds, shift values

                                              `to the DISPLAY array.

    Display(x,y)=Grid(x+currentx,y+currenty)

  endif

  `if Display(x,y)=1 then paste image 1,x*TileSize,y*TileSize,1

  if Display(x,y)=2 then paste image 2,x*TileSize,y*TileSize

  if Display(x,y)=3 then paste image 3,x*TileSize,y*TileSize

  if Display(x,y)=4 then paste image 4,x*TileSize,y*TileSize

  if Display(x,y)=5 then paste image 5,x*TileSize,y*TileSize

  if Display(x,y)=6 then paste image 6,x*TileSize,y*TileSize

next x

next y

 

`Here we paste onto the screen based on its position and the TileSize for our level.

HeroPositionx=herox*TileSize

HeroPositiony=(heroy*TileSize)

paste image Hero,HeroPositionx,HeroPositiony,1

 

 

`This is just a simple text statement to help show us the values of each tile in the

`DISPLAY array. This will become especially useful when we get really in-depth with our

`collisions, to make sure that everything is working properly.

if spacekey()=0

for x=0 to Dimensions

for y=0 to Dimensions

 text x*TileSize,y*TileSize,str$(Display(x,y))

next x

next y

endif

 

`Our current TileX and TileY the mouse is over.

position mouse (HeroPositionx+TileSize),(HeroPositiony+TileSize)

 

TileX=((mousex()+(currentx*32))/TileSize)*1.0

TileY=((mousey()+(currenty*32))/TileSize)*1.0

`The relative TileX and TileY we're over in our Display array.

relativeTileX=(mousex()/TileSize)*1.0

relativeTileY=(mousey()/TileSize)*1.0

 

`Here's a little bit of debugging, showing the tiles our mouse is over.

text 580,0,str$(currentx+relativeTileX)+","+str$(currenty+relativeTileY)

text 580,40,str$(relativeTileX)+","+str$(relativeTileY)

text 580,80,str$(Dimensions) `Shows the map dimensions

text 580,100,str$(TileSize)  `Shows the TileSize

text 580,120,str$(MapSize)   `Shows the mapsize.

text 580,140,str$(startx)+","+str$(starty) `Starting x and y positions

text 580,160,str$(herox)+","+str$(heroy)   `Heroes current position

text 580,180,str$(screen fps())            `The Frames per second our program is running.

 

sync ` refresh our screen.

loop ` Go back to our do, and start all over!

 

 

 

Section 6 - Notes and Closing

 

Contact: yellow1dbp@hotmail.com

 

Notes:

 

-         Slow performance? Try decreasing the resolution, the mapsize, the dimensions, the tile size, and running in full screen exclusive mode.

-         Still slow performance? Make sure you don’t have any/many other programs running the background while you program. J

 

What’s to come?

 

-         Next newsletter will be dedicated to the concepts of pixel-perfect collision, and how it’ll play it’s roll into Tile Engine games.  We’ll also expand onto our tile editor, and I’ll talk about positioning enemies.  Finally, we’ll build the user interface for the game.

 

Until the next tutorial, keep reading, practicing, and most of all, playing with code.

 

Mike Shah